package com.cjm.one.custom.apps.controller;

import cn.hutool.jwt.JWT;
import com.cjm.one.common.constant.RedisConstants;
import com.cjm.one.common.constant.TokenConstants;
import com.cjm.one.common.exception.GlobalException;
import com.cjm.one.common.result.Result;
import com.cjm.one.common.result.ResultCodeEnum;
import com.cjm.one.common.utils.AuthCustomerContextHolder;
import com.cjm.one.common.utils.JSONUtils;
import com.cjm.one.custom.service.CustomerInfoService;
import com.cjm.one.model.custom.dto.BindEmailDto;
import com.cjm.one.model.custom.dto.PasswordSetDto;
import com.cjm.one.model.custom.dto.PayPasswordSetDto;
import com.cjm.one.model.custom.entity.CustomerInfo;
import com.cjm.one.model.payment.BalanceDto;
import com.cjm.one.security.annotation.Within;
import com.cjm.one.security.custom.CustomPasswordEncoder;
import com.cjm.one.security.custom.SaltGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.micrometer.common.util.StringUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Min;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
@Tag(name = "用户详情")
@RequestMapping("/app/customer/info")
public class AppCustomInfoController {

    @Resource
    private CustomerInfoService customerInfoService;
    @Resource
    @Qualifier("appPasswordEncoder")
    private PasswordEncoder customPasswordEncoder;

    @Resource
    private RedisTemplate redisTemplate;

    @PutMapping("/update")
    @Operation(summary = "更新用户信息")
    public Result<CustomerInfo> getCustomerInfo(@RequestBody CustomerInfo customerInfo) {
            log.debug("更新用户信息：{}", customerInfo);
        Long id = AuthCustomerContextHolder.getAuthContextCustomer().getId();
        customerInfo.setId(id);
        boolean b = customerInfoService.updateById(customerInfo);
        if(!b){
            throw new GlobalException(ResultCodeEnum.UPDATE_CUSTOMER_FAIL);
        }
        CustomerInfo customerInfoData = customerInfoService.getById(id);
        customerInfoData.setPassword(null);
        customerInfoData.setSalt(null);
        customerInfoData.setPayPassword(null);
        customerInfoData.setPaySalt(null);
        return Result.ok(customerInfoData);
    }

    @PostMapping("/passwordSet")
    @Operation(summary = "修改密码")
    public Result<Boolean> passwordSet(@RequestBody PasswordSetDto passwordSetDto) {
        CustomerInfo authContextCustomer = AuthCustomerContextHolder.getAuthContextCustomer();
//        String code = passwordSetDto.getCode();
//        String redisCode = (String)redisTemplate.opsForValue().get(RedisConstants.CAPTCHA_SMSCODE_KEY_EXPIRE + passwordSetDto.getEmail());
//        if (redisCode == null || !redisCode.equals(code)) {
//            throw new GlobalException(ResultCodeEnum.EMAIL_CODE_EXPIRED);
//        }
//        if (!code.equals(redisCode)){
//            throw new GlobalException(ResultCodeEnum.EMAIL_CODE_MISMATCH);
//        }
        String oldPassword = passwordSetDto.getOldPassword();
        if(!StringUtils.isEmpty(oldPassword)){
            boolean matches = customPasswordEncoder.matches(oldPassword+authContextCustomer.getSalt(), authContextCustomer.getPassword());
            if(!matches){
                throw new GlobalException(ResultCodeEnum.PASSWORD_ERROR);
            }
        }
        String salt = SaltGenerator.generateSalt();
        String encodePassword = customPasswordEncoder.encode(passwordSetDto.getNewPassword() + salt);
        CustomerInfo customerInfo = new CustomerInfo();
        customerInfo.setId(authContextCustomer.getId());
        customerInfo.setPassword(encodePassword);
        customerInfo.setSalt(salt);
        log.debug("更新用户密码：{}", customerInfo);
        return Result.ok(customerInfoService.updateById(customerInfo));
    }

    @PostMapping("/payPasswordSet")
    @Operation(summary = "修改支付密码")
    public Result<Boolean> payPasswordSet(@Validated @RequestBody PayPasswordSetDto passwordSetDto) {
        CustomerInfo authContextCustomer = AuthCustomerContextHolder.getAuthContextCustomer();
//        String code = passwordSetDto.getCode();
//        String redisCode = (String) redisTemplate.opsForValue().get(RedisConstants.CAPTCHA_MOBLECODE_KEY_EXPIRE + passwordSetDto.getEmail());
//        if (redisCode == null) {
//            throw new GlobalException(ResultCodeEnum.EMAIL_CODE_EXPIRED);
//        }
//        if (!redisCode.equals(code)) {
//            throw new GlobalException(ResultCodeEnum.EMAIL_CODE_MISMATCH);
//        }

        String oldPassword = passwordSetDto.getOldPassword();
        if (!StringUtils.isEmpty(oldPassword)) {
            boolean matches = customPasswordEncoder.matches(oldPassword + authContextCustomer.getPaySalt(), authContextCustomer.getPayPassword());
            if (!matches) {
                throw new GlobalException(ResultCodeEnum.PASSWORD_ERROR);
            }
        }

        String paySalt = SaltGenerator.generateSalt();
        String newPayPassword = customPasswordEncoder.encode(passwordSetDto.getNewPassword() + paySalt);
        CustomerInfo customerInfo = new CustomerInfo();
        customerInfo.setId(authContextCustomer.getId());
        customerInfo.setPayPassword(newPayPassword);
        customerInfo.setPaySalt(paySalt);
        log.debug("更新用户支付密码：{}", customerInfo);
        return Result.ok(customerInfoService.updateById(customerInfo));
    }

    @PostMapping("/bindEmailSet")
    @Operation(summary = "绑定邮箱")
    public Result<String> bindEmailSet(@Validated @RequestBody BindEmailDto passwordSetDto) throws JsonProcessingException {
        CustomerInfo authContextCustomer = AuthCustomerContextHolder.getAuthContextCustomer();
        String code = passwordSetDto.getCode();
        String redisCode = (String) redisTemplate.opsForValue().get(RedisConstants.CAPTCHA_SMSCODE_KEY_EXPIRE + passwordSetDto.getEmail());
        if (redisCode == null) {
            throw new GlobalException(ResultCodeEnum.EMAIL_CODE_EXPIRED);
        }
        if (!redisCode.equals(code)) {
            throw new GlobalException(ResultCodeEnum.EMAIL_CODE_MISMATCH);
        }
        authContextCustomer.setEmail(passwordSetDto.getEmail());
        AuthCustomerContextHolder.setAuthContextCustomer(authContextCustomer);
        boolean b = customerInfoService.updateById(authContextCustomer);
        if(!b){
            throw new GlobalException(ResultCodeEnum.UPDATE_CUSTOMER_FAIL);
        }
        String token =  JWT.create()
                .setSigner(TokenConstants.SIGNER)
                .setPayload(TokenConstants.APP_USER, authContextCustomer)
                .sign();
        log.info("生成的token:{}",token);
        //将用户信息放入到redis
        redisTemplate.opsForValue().set(RedisConstants.APP_USER_LOGIN_KEY_TOKEN + token,
                JSONUtils.toString(authContextCustomer) ,
                TokenConstants.TOKEN_EXPIRATION_TIME,
                TimeUnit.SECONDS);
        log.debug("更新用户邮箱：{}", authContextCustomer);
        return Result.ok(token);
    }

    @PostMapping("/addBalance/{value}")
    @Operation(summary = "充值余额虚假接口，测试用")
    public Result<Boolean> addBalance(@PathVariable("value") @Validated @Min(0) BigDecimal value){
        Long id = AuthCustomerContextHolder.getAuthContextCustomer().getId();

        return Result.ok(customerInfoService.addBalance(id, value));
    }
    @PostMapping("/pay")
    @Operation(summary = "支付虚假接口，测试用")
    public Result<Long> pay(@RequestBody BalanceDto balanceDto){
        log.info("支付信息：{}", balanceDto);
        return Result.ok(customerInfoService.pay(balanceDto));
    }


}
